package com.cango.student.disruptor.disruptor;

import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.BusySpinWaitStrategy;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * - BlockingWaitStrategy：默认等待策略。和BlockingQueue的实现很类似，通过使用锁和条件（Condition）进行线程同步和唤醒。
 *  此策略对于线程切换来说，最节约CPU资源，但在高并发场景下性能有限。
 * - SleepingWaitStrategy：CPU友好型策略。会在循环中不断等待数据。首先进行自旋等待，
 * 若不成功，则使用Thread.yield()让出CPU，并使用LockSupport.parkNanos(1)进行线程睡眠。
 * 所以，此策略数据处理数据可能会有较高的延迟，适合用于对延迟不敏感的场景。优点是对生产者线程影响小，典型应用场景是异步日志。
 * - YieldingWaitStrategy：低延时策略。消费者线程会不断循环监控RingBuffer的变化，在循环内部使用Thread.yield()让出CPU给其他线程。
 * - BusySpinWaitStrategy：死循环策略。消费者线程会尽最大可能监控缓冲区的变化，会占用所有CPU资源。

 */
public class DisruptorMain {
    public static void main(String[] args) {
        DisruptorFactory factory = new DisruptorFactory();          // 工厂
        ExecutorService executor = Executors.newCachedThreadPool(); // 线程池
        int BUFFER_SIZE = 16;   // 必须为2的幂指数

        // 初始化Disruptor
        Disruptor<FileData> disruptor = new Disruptor<>(factory,
                BUFFER_SIZE,
                executor,
                ProducerType.MULTI,         // Create a RingBuffer supporting multiple event publishers to the one RingBuffer
//                new BlockingWaitStrategy()  // 默认阻塞策略
                new BusySpinWaitStrategy()
        );
        // 启动消费者
//        disruptor.handleEventsWithWorkerPool(new DisruptorConsumer(),
//                new DisruptorConsumer()
//        );
        disruptor.handleEventsWithWorkerPool(new DisruptorConsumer());
        disruptor.start();
        // 启动生产者
        RingBuffer<FileData> ringBuffer = disruptor.getRingBuffer();
        DisruptorProducer producer = new DisruptorProducer(ringBuffer);
        producer.read("D:\\temp.dat");

        // 关闭
        disruptor.shutdown();
        executor.shutdown();
    }
}
